package org.ccay.vfs;


import java.io.File;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.vfs2.CacheStrategy;
import org.apache.commons.vfs2.FileContentInfoFactory;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemManager;
import org.apache.commons.vfs2.FilesCache;
import org.apache.commons.vfs2.impl.DefaultFileReplicator;
import org.apache.commons.vfs2.impl.StandardFileSystemManager;
import org.apache.commons.vfs2.provider.FileProvider;
import org.apache.commons.vfs2.provider.TemporaryFileStore;
import org.ccay.core.util.StringUtil;
import org.ccay.registry.util.RegistryQueryUtil;
import org.springframework.beans.factory.FactoryBean;

/**
 * 包装FileSystemManager的创建过程，便于Spring的使用
 * @author chaowangbang
 *
 */
public class FileSystemManagerFactoryBean implements FactoryBean<FileSystemManager>{
	
	private String tempDir ;
	
	private FileSystemManager fileSystemManager;
	
	/**
	 * The default provider.
	 */
	private FileProvider defaultProvider;
	
    /**
     * Sets the default provider. This is the provider that will handle URI with
     * unknown schemes. The manager takes care of all lifecycle management.
     * @param provider The FileProvider.
     * @throws FileSystemException if an error occurs setting the provider.
     */
    public void setDefaultProvider(final FileProvider provider)
            throws FileSystemException
    {
        defaultProvider = provider;
    }
	
	/**
	 * Customed addtion FileProvider
	 */
	private Map <String,FileProvider> addtionProviders;
	
    /**
     * Sets Customed addtion FileProvider
     * @param addtionProviders
     */
    public void setAddtionProviders(Map<String, FileProvider> addtionProviders) {
		this.addtionProviders = addtionProviders;
	}

	/**
     * The file replicator to use.
     */
    private DefaultFileReplicator fileReplicator;
    
    /**
     * Sets the file replicator to use.
     * <p>
     * The manager takes care of all lifecycle management.
     *
     * @param replicator The FileReplicator.
     * @throws FileSystemException if an error occurs setting the replicator.
     */
    public void setReplicator(final DefaultFileReplicator replicator)
            throws FileSystemException
    {
        fileReplicator = replicator;
    }
    
    
	
	 /**
     * The class to use to determine the content-type (mime-type)
     */
    private FileContentInfoFactory fileContentInfoFactory;
    
    /**
     * set the fileContentInfoFactory used to determine the infos of a file
     * content.
     * <p>
     * Can only be set before the FileSystemManager is initialized.
     *
     * @param fileContentInfoFactory The FileContentInfoFactory.
     * @throws FileSystemException if an error occurs setting the FileContentInfoFactory.
     */
    public void setFileContentInfoFactory(final FileContentInfoFactory fileContentInfoFactory)
            throws FileSystemException
    {

        this.fileContentInfoFactory = fileContentInfoFactory;
    }
    
    
    /**
     * The files cache
     */
    private FilesCache filesCache;
    
    /**
     * Sets the filesCache implementation used to cache files.
     * <p>
     * Can only be set before the FileSystemManager is initialized.
     * <p>
     * The manager takes care of the lifecycle. If none is set, a default is picked
     * in {@link #init()}.
     *
     * @param filesCache The FilesCache.
     * @throws FileSystemException if an error occurs setting the cache..
     */
    public void setFilesCache(final FilesCache filesCache)
            throws FileSystemException
    {

        this.filesCache = filesCache;
    }

    /**
     * The cache strategy
     */
    private CacheStrategy fileCacheStrategy;
    
    /**
     * Set the cache strategy to use when dealing with file object data.
     * <p>
     * Can only be set before the FileSystemManager is initialized.
     * <p>
     * The default is {@link CacheStrategy#ON_RESOLVE}
     *
     * @param fileCacheStrategy The CacheStrategy to use.
     * @throws FileSystemException
     *             if this is not possible. e.g. it is already set.
     */
    public void setCacheStrategy(final CacheStrategy fileCacheStrategy)
            throws FileSystemException
    {

        this.fileCacheStrategy = fileCacheStrategy;
    }
    
    private String configUri;
    
    /**
     * Sets the configuration file for this manager.
     *
     * @param configUri The URI for this manager.
     */
    public void setConfiguration(final String configUri)
    {
    	this.configUri = configUri;
    }
    
    private ClassLoader classLoader;
    
    /**
     * Sets the ClassLoader to use to load the providers.
     * Default is to use the ClassLoader that loaded this class.
     *
     * @param classLoader The ClassLoader.
     */
    public void setClassLoader(final ClassLoader classLoader)
    {
        this.classLoader = classLoader;
    }
	
	/**
	 * A standard FactoryBean is not expected to initialize eagerly:
	 * Its {@link #getObject()} will only be called for actual access, even
	 * in case of a singleton object.
	 */
	@Override
	public FileSystemManager getObject() throws Exception {
	  if (this.fileSystemManager == null) {
		  buildFileSystemManager(); 
	    }
	    return this.fileSystemManager;
	}

	@Override
	public Class<?> getObjectType() {
		return FileSystemManager.class;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}

	public String getTempDir() {
		return tempDir;
	}

	/**
	 * 设置临时文件存储目录
	 * @param tempDir
	 */
	public void setTempDir(String tempDir) {
		this.tempDir = tempDir;
	}
	
	/**
	 * 创建systemManager
	 * @throws FileSystemException
	 */
	/**
	 * @throws FileSystemException
	 */
	protected void buildFileSystemManager() throws FileSystemException {
		StandardFileSystemManager sfs = new StandardFileSystemManager();
		if(addtionProviders != null){
			for(Entry<String, FileProvider> entry : addtionProviders.entrySet()){
				sfs.addProvider(entry.getKey(), entry.getValue());
			}
		}
		if(null != defaultProvider){
			sfs.setDefaultProvider(defaultProvider);
		}
	
		if(null != fileContentInfoFactory){
			sfs.setFileContentInfoFactory(fileContentInfoFactory);
		}
		if(null != filesCache){
			sfs.setFilesCache(filesCache);
		}
		if(null != fileCacheStrategy){
			sfs.setCacheStrategy(fileCacheStrategy);
		}
		if(null != configUri){
			sfs.setConfiguration(configUri);
		}
		if(null != classLoader){
			sfs.setClassLoader(classLoader);
		}
		
		sfs.init();
		
		fileSystemManager = sfs;
	}

	
	public class CcayFileSystemManager extends StandardFileSystemManager{
		
	    protected DefaultFileReplicator createDefaultFileReplicator()
	    {
	    	if(fileReplicator != null){
	    		return fileReplicator;
	    	}
	    	if(tempDir == null){
	    		String regTempDir = RegistryQueryUtil.getValue(VFS.TEMP_DIR_REGISTRY_NAME);
	    		if(!StringUtil.isNullOrEmpty(regTempDir)){
	    			tempDir = regTempDir;
	    		}
	    	}
	    	if(tempDir == null){
	    		tempDir = System.getProperty("java.io.tmpdir");
	    	}
	        return new DefaultFileReplicator(new File(tempDir, "vfs_cache").getAbsoluteFile());
	    }
	}
}